package mc0458.b;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.StreamTokenizer;

//线段树节点
class Tree {
	public int l; // 节点表示区间的左界
	public int r; // 节点表示区间的右届
	public int val; // 原始值的下标
	public int size; // 当前节点子树对应的数据大小

	public Tree(int l, int r) {
		this.l = l;
		this.r = r;
	}
}

public class Main {
	static final int N = (int) 1e6 + 10;
	static int[] a = new int[N];
	static final long INF = (long) 1e18;
	static Tree[] t = new Tree[4 * N];

	// 返回左儿子编号，参数p为父节点编号
	public static int lc(int p) {
		// 左儿子编号p*2
		return p << 1; // 位运算提高效率，用p*2也行，更直观
	}

	// 返回右儿子编号，参数p为父节点编号
	public static int rc(int p) {
		// 右儿子编号p*2+1
		return p << 1 | 1; // 位运算提高效率，用p*2+1也行，更直观
	}

	// 更新节点信息
	static void pushUp(int p) {
		// size为子节点size和
		t[p].size = t[lc(p)].size + t[rc(p)].size;

		// val保存左右子树中原数组值最大的下标
		if (a[t[lc(p)].val] < a[t[rc(p)].val]) {
			t[p].val = t[rc(p)].val;
		} else {
			t[p].val = t[lc(p)].val;
		}
	}

	// 建立线段树
	static void build(int p, int l, int r) {
		t[p] = new Tree(l, r);
		if (l == r) {
			t[p].size = 1;
			t[p].val = l;
			return;
		}
		int mid = (l + r) / 2;
		build(lc(p), l, mid);
		build(rc(p), mid + 1, r);
		pushUp(p);
	}

	// 查询区间最大值的下标
	// [l,r]为目标区间
	// 标准线段树查询方法
	static int query(int p, int l, int r) {
		// 查询区间在当前节点外
		if (l > t[p].r || r < t[p].l) {
			return 0;
		}
		// 查询区间在当前节点内
		if (l <= t[p].l && t[p].r <= r) {
			// 返回当前节点维护的值
			return t[p].val;
		}
		// 当前节点区间中点
		int mid = (t[p].l + t[p].r) / 2;
		// 左子树继续查询
		int val1 = query(lc(p), l, r);
		// 右子树继续查询
		int val2 = query(rc(p), l, r);

		// 左右子树，返回原数组值大的下标
		if (a[val1] < a[val2]) {
			return val2;
		} else {
			return val1;
		}
	}

	// 将指定下标标记为已使用
	// 标准线段树单点修改
	static void update(int p,int i) {
		if (i > t[p].r || i < t[p].l) {
			return;
		}
		//找到目标节点
		if (t[p].l == t[p].r) {
			//该位置的数使用后下标设为0，size设为0
			t[p].val = 0;
			t[p].size = 0;
			return;
		}
		
		update(lc(p), i);
		update(rc(p), i);
		pushUp(p);
	}

	//k表示能触及的最远位置
	//根据k找出能触及的原数组的最远pos
	static int findPos(int p, long k) {
		//找到叶子节点，返回原数组位置
		if (t[p].l == t[p].r) {
			return t[p].l;
		}
		int mid = (t[p].l + t[p].r) / 2;
		if (k <= t[lc(p)].size) {
			return findPos(lc(p), k);
		} else {
			return findPos(rc(p), k - t[lc(p)].size);
		}
	}

	// pos位置移动到最前需要的移动次数
	static long count(int p, int l, int r) {
		// 查询区间在当前节点外
		if (t[p].l > r || t[p].r < l) {
			return 0;
		}
		// 查询区间在节点内
		if (l <= t[p].l && t[p].r <= r) {
			return t[p].size;
		}
		//查询区间跨两个节点
		return count(lc(p), l, r) + count(rc(p), l, r);
	}

	// 输入优化模板开始
	static BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
	static StreamTokenizer st = new StreamTokenizer(br);

	static int rd() throws IOException {
		st.nextToken();
		return (int) st.nval;
	}

	// 输入优化模板结束
	// 输出优化
	static StringBuilder sb = new StringBuilder();

	public static void main(String[] args) throws IOException {
		String[] lineArr = br.readLine().split(" ");

		int n = Integer.parseInt(lineArr[0]);
		long m = Long.parseLong(lineArr[1]);

		for (int i = 1; i <= n; i++) {
			a[i] = rd();
		}
		// 建立线段树
		build(1, 1, n);
		// 保存答案
		int[] ans = new int[n + 1];
		for (int i = 1; i <= n; i++) {
			//k表示交换次数m限制下能触及的最远位置
			long k = Math.min(t[1].size, m + 1);
			//根据k找出能触及的原数组的最远pos
			int pos = findPos(1, k);
			//查找当前[1,pos]区间的代表原数组最大值的下标
			int j = query(1, 1, pos);
			//保存最大值
			ans[i] = a[j];
			//计算消耗的移动次数
			m -= count(1, 1, j - 1);
			//单点修改线段树将移出项对应的下标置为0
			update(1, j);
		}
		for (int i = 1; i <= n; i++) {
			sb.append(ans[i]);
			sb.append(" ");
		}

		System.out.print(sb.toString());
	}
}
